home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / wais / waisgate / sockets.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  8KB  |  329 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE    
  2.    No guarantees or restrictions.  See the readme file for the full standard 
  3.    disclaimer.  
  4.    5.29.90    Harry Morris, morris@think.com
  5. */
  6.  
  7. #ifndef lint
  8. static char *RCSid = "$Header: /tmp_mnt/net/quake/proj/wais/wais-8-b5/ir/RCS/sockets.c,v 1.23 92/05/06 17:34:41 jonathan Exp $";
  9. #endif
  10.  
  11. /* Change log:
  12.  * $Log:    sockets.c,v $
  13.  * Revision 1.23  92/05/06  17:34:41  jonathan
  14.  * Added Mach to some compiler switches.
  15.  * 
  16.  * Revision 1.22  92/04/28  15:21:14  jonathan
  17.  * Added decoding of IP address to DNS name in accept_client handler.
  18.  * 
  19.  * Revision 1.21  92/04/01  09:49:49  morris
  20.  * declared clr_socket static to stop gcc from complaining
  21.  * 
  22.  * Revision 1.20  92/03/24  10:35:32  jonathan
  23.  * Put a loop around connect in fd_connect_to_server to check if the connect
  24.  * was interrupted by a system call (usually a timer).  Retries if errno is
  25.  * EINTR.
  26.  * 
  27.  * Revision 1.19  92/02/16  12:38:22  jonathan
  28.  * Changed bzero's to memset's.
  29.  * 
  30.  * Revision 1.18  92/02/16  12:34:11  jonathan
  31.  * Removed code refering to NOINETNTOA, since we should use inet_ntoa.
  32.  * 
  33.  * Revision 1.17  92/02/12  13:48:21  jonathan
  34.  * Added "$Log" so RCS will put the log message in the header
  35.  * 
  36.  * 
  37. */
  38.  
  39. /*
  40.    Added code in fd_accept_client_connection to print source Inet address to
  41.    stderr. 
  42.    - Jonny G Fri Apr 12 1991
  43.  
  44. */
  45.  
  46. #define sockets_c
  47.  
  48. #include "sockets.h"
  49.  
  50. #ifdef NOTCPIP /* we don't have TCPIP */
  51.  
  52. void open_server (port,socket,size) long port; long* socket; long size; {}
  53. void accept_client_connection (socket,file) long socket; FILE** file; {}
  54. void close_client_connection (file) FILE* file; {}
  55. void close_server (socket) long socket; {}
  56. FILE *connect_to_server (host_name,port) char* host_name; long port; 
  57.                                   {return(NULL);}
  58. void close_connection_to_server (file) FILE* file; {}
  59.  
  60. #else /* there is TCPIP */
  61.  
  62. #include <errno.h>
  63. #include <string.h>
  64. #include "panic.h"
  65.  
  66. #if (defined(ultrix) || defined(BSD) || defined(Mach))
  67. extern int errno;
  68. #endif /* ultrix BSD or Mach */
  69.  
  70. extern char *sys_errlist[];
  71.  
  72.  
  73. /* XXX
  74. still need:
  75.  non-blocking modes
  76.  special send/recieve functions? (there are now some in ui.c)
  77.  asynchronous calls?
  78. */
  79.  
  80. /* define the number of queued connections allowable on each port */
  81. #define QUEUE_SIZE 3
  82.  
  83. /*---------------------------------------------------------------------------*/
  84. /* Server functions                                                          */
  85. /*---------------------------------------------------------------------------*/
  86.  
  87. static boolean clr_socket _AP((struct sockaddr_in *address, long portnumber,
  88.             long* sock));
  89.  
  90. static boolean clr_socket(address, portnumber, sock)
  91.      struct sockaddr_in *address;
  92.      long portnumber;
  93.      long *sock;
  94. {
  95.   if (errno == EADDRINUSE) {
  96.     /* Try connecting to it */
  97.     if (connect(*sock, address, sizeof (struct sockaddr_in)) == 0) {
  98.       close(*sock);
  99.       waislog(WLOG_HIGH, WLOG_ERROR,
  100.           "Cannot bind port %ld: (Address already in use).",
  101.           portnumber);
  102.       waislog(WLOG_HIGH, WLOG_ERROR, "waisserver is already running on this system");
  103.       panic("Exiting");
  104.     } else {
  105.       /* Connection failed; probably socket in FIN_WAIT */
  106.       int one = 1;
  107.  
  108.       (void) close(*sock);
  109.       if ((*sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  110.     panic("Open socket failed in trying to clear the port.");
  111.       /*printf("Error binding port %d: (address already in use).\n\
  112. Attempting to clear stale socket...", portnumber);*/
  113.       if ( setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, 
  114.               &one, sizeof (one)) < 0) {
  115.     /*printf("Warning: Setsockopt SO_REUSEADDR failed.");*/
  116.       }
  117.       address->sin_family = AF_INET;
  118.       address->sin_addr.s_addr = INADDR_ANY;
  119.       address->sin_port = htons(portnumber);
  120.       if (bind(*sock, address, sizeof(*address)) == 0) {
  121.     /*printf("Successfully cleared stale EADDRINUSE error");*/
  122.       }
  123.     }
  124.   }
  125.   return(true);
  126. }
  127.  
  128.  
  129. void
  130. open_server(port,fd,size)
  131. long port;
  132. long* fd;
  133. long size;
  134. { struct sockaddr_in address;
  135.  
  136.   memset(&address, 0, sizeof(address));
  137.  
  138.   /* open the fd */
  139.   if ((*fd = socket(AF_INET,SOCK_STREAM,0)) < 0){
  140.     panic("can't get file descriptor for socket: %s", sys_errlist[errno]);
  141.   }
  142.  
  143.   address.sin_family = AF_INET;
  144.   address.sin_addr.s_addr = htonl(INADDR_ANY);
  145.   address.sin_port = htons(port);
  146.   if (bind(*fd,(struct sockaddr*)&address,sizeof(struct sockaddr)) < 0)
  147.     clr_socket(&address, port, fd);
  148.  
  149.   if (listen(*fd,QUEUE_SIZE) < 0)
  150.     panic("can't open server: %s", sys_errlist[errno]);
  151. }
  152.  
  153.  
  154.  
  155. /* This is a lower level function provided for use by the lisp version of
  156.  * this library 
  157.  * XXX should support non-blocking mode
  158.  */
  159.  
  160. #include <arpa/inet.h>
  161.  
  162. void
  163. fd_accept_client_connection(socket,fd)
  164. long socket;
  165. long* fd;
  166. { /* accept an input connection, and open a file on it */
  167.   struct sockaddr_in source;
  168.   int sourcelen;
  169. #ifdef BSD
  170.   struct in_addr {
  171.     union {
  172.       struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
  173.       u_long S_addr;
  174.     } S_un;
  175.   } addr_p;
  176. #endif /* BSD */
  177.  
  178.   sourcelen = sizeof(struct sockaddr_in);
  179.  
  180.   do {
  181.     errno = 0;
  182.     *fd = accept(socket, &source, &sourcelen);
  183.   } while (*fd < 0 && errno == EINTR);
  184.  
  185.   if(source.sin_family == AF_INET) {
  186.     struct hostent *peer = NULL;
  187.  
  188.     peer = gethostbyaddr(&source.sin_addr, 4, AF_INET);
  189.  
  190.     waislog(WLOG_MEDIUM, WLOG_CONNECT,
  191.         "Accepted connection from: %s [%s]",
  192.         peer->h_name,
  193. #if defined(sparc) && defined(__GNUC__)
  194.         inet_ntoa(&source.sin_addr)
  195. #else
  196.         inet_ntoa(source.sin_addr)
  197. #endif /* sparc */
  198.         );
  199.   }
  200.   if (*fd < 0)
  201.     panic("can't accept connection");
  202. }
  203.  
  204.  
  205. /* This is the prefered C function for accepting client requests */
  206. void
  207. accept_client_connection(socket,file)
  208. long socket;
  209. FILE** file;
  210. { long fd; /* file descriptor actually used */
  211.   fd_accept_client_connection(socket,&fd);
  212.   if ((*file = fdopen(fd,"r+")) == NULL)
  213.     panic("can't accept connection");
  214. }
  215.  
  216. /* When a server wants to end the session with a client */
  217. void
  218. close_client_connection(file)
  219. FILE* file;
  220.   fclose(file);
  221. }
  222.  
  223. /* when exiting the top level server process (not the forked
  224.    server processes that come one per client).
  225.    Maybe we need to do this once per client as well.
  226. */
  227. void
  228. close_server(socket)
  229. long socket;
  230. {
  231.   close(socket);
  232. }
  233.  
  234. /*---------------------------------------------------------------------------*/
  235. /* Client functions                                                          */
  236. /*---------------------------------------------------------------------------*/
  237.  
  238. /* This is a lower level function provided for use by the lisp version of
  239.  * this library 
  240.  * XXX should support non-blocking mode
  241.  */
  242.  
  243. #define HOSTNAME_BUFFER_SIZE 120
  244. #define MAX_RETRYS 10
  245.  
  246. boolean
  247. fd_connect_to_server(host_name,port,fd)
  248. char* host_name;
  249. long port;
  250. long* fd;
  251. {
  252.   char hostnamebuf[80];
  253.   long rc, i;
  254.   struct hostent *host;
  255.   /* struct servent *service = NULL; not used */
  256.   struct sockaddr_in name;
  257.  
  258.   memset((char *)&name, 0,sizeof (name));
  259.   name.sin_addr.s_addr = inet_addr(host_name);
  260.   if (name.sin_addr.s_addr != -1) {
  261.     name.sin_family = AF_INET;
  262.     (void) strcpy(hostnamebuf, host_name);
  263.   }
  264.   else {
  265.     host = gethostbyname(host_name);
  266.  
  267.     if(NULL == host){
  268.       return FALSE;
  269.     }
  270.  
  271.     name.sin_family = host->h_addrtype;
  272. #ifdef h_addr
  273.     bcopy(host->h_addr_list[0],
  274.       (caddr_t)&name.sin_addr, host->h_length);
  275. #endif
  276.     (void) strcpy(hostnamebuf, host->h_name);
  277.   }
  278.   host_name = hostnamebuf;
  279.  
  280.   name.sin_port = htons(port);
  281.  
  282.   *fd = socket (AF_INET, SOCK_STREAM, 0);
  283.   for(i = 0; i < MAX_RETRYS; i++) {
  284.     rc = connect (*fd, &name, sizeof (name));
  285.     if(rc == 0) return TRUE;
  286.     else if(errno == EINTR){
  287.       sleep(1);
  288.     }
  289.     else {
  290.       perror("Connect to socket did not work (1)");
  291.       return FALSE;
  292.     }
  293.   }
  294.   return FALSE;
  295. }
  296.  
  297. /* This is the prefered C function for initiating client requests */
  298. FILE *
  299. connect_to_server(host_name,port)
  300. char* host_name;
  301. long port;
  302. {
  303.   FILE* file;
  304.   long fd;
  305.   if(fd_connect_to_server(host_name,port,&fd) == FALSE) {
  306.     perror("Connect to socket did not work (2)");
  307.     return NULL;
  308.   }
  309.  
  310.   if ((file = fdopen(fd,"r+")) == NULL) {
  311.     perror("Connect to socket did not work (3)");
  312.     return NULL;
  313.   }
  314.  
  315.   return file;
  316. }
  317.  
  318. void
  319. close_connection_to_server(file)
  320. FILE* file;
  321. {
  322.   fclose(file);
  323. }
  324.  
  325. /*---------------------------------------------------------------------------*/
  326.  
  327. #endif /* there is TCPIP */
  328.